package ace.system;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import javax.microedition.lcdui.Image;

import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;

public class Utilities {
	//Game constants
	public static final int GAME_FPS 			= 30;
	public static final int GAME_BUTTON_WAIT 	= 200;
	
	//Gameplay constants
	public static final int TILE_WIDTH			= 32;
	public static final int TILE_HEIGHT			= 32;
	public static final int TILESET_COLUMN		= 8;
    public static final int MAX_LEVEL           = 10;
    public static final int MAX_SHOT_SPREAD     = 10;
    public static final int MAX_SHOT_SPLIT      = 10;

	//Fonder constants
	public static final String DATA_FOLDER			= "/data";
	public static final String FONT_FOLDER			= "/fonts";
	public static final String IMAGE_FOLDER			= "/images";
	public static final String AUDIO_FOLDER			= "/audio";
	public static final String LEVEL_FOLDER			= DATA_FOLDER + "/levels";
	public static final String STRING_FOLDER		= DATA_FOLDER + "/strings";
	public static final String ENEMY_FOLDER			= IMAGE_FOLDER + "/enemies";
	public static final String BULLET_FOLDER		= IMAGE_FOLDER + "/bullets";
	public static final String PICKUP_FOLDER		= IMAGE_FOLDER + "/pickups";
	public static final String WEAPON_FOLDER		= IMAGE_FOLDER + "/weapons";
	public static final String BODY_FOLDER			= IMAGE_FOLDER + "/bodies";
	public static final String TILESET_FOLDER		= IMAGE_FOLDER + "/tilesets";
	public static final String INTERFACE_FOLDER		= IMAGE_FOLDER + "/interface";
	public static final String BACKGROUND_FOLDER	= IMAGE_FOLDER + "/backgrounds";
	public static final String BGM_FOLDER			= AUDIO_FOLDER + "/bgm";
	public static final String SFX_FOLDER			= AUDIO_FOLDER + "/sfx";

	//Resource constants
	public static final String TINTDATA_FILE	= DATA_FOLDER + "/tints.xml";
	public static final String LEVELINFO_FILE	= DATA_FOLDER + "/levellist.xml";
	public static final String BODY_FILE		= DATA_FOLDER + "/bodies.xml";
	public static final String WEAPON_FILE		= DATA_FOLDER + "/weapons.xml";
	public static final String ENEMY_FILE		= DATA_FOLDER + "/enemies.xml";
	public static final String PICKUP_FILE		= DATA_FOLDER + "/pickups.xml";

	//Images
	public static final String TILE_IMAGE		= INTERFACE_FOLDER + "/tile.png";
	public static final String TOWERPANEL_IMAGE	= INTERFACE_FOLDER + "/panel.png";
	public static final String PANELARROW_IMAGE = INTERFACE_FOLDER + "/arrow.png";

	//Fonts constants
	public static final String MAIN_FONT	= FONT_FOLDER + "/gautami.font";
	public static final String TITLE_FONT	= FONT_FOLDER + "/hammerhead.font";
	public static final String TITLE_BIG_FONT	= FONT_FOLDER + "/hammerhead_big.font";
	public static final String BITSUMISHI_BLUE	= FONT_FOLDER + "/bitsumishi.font";
	
	//RMS name constant
	public static final String	RMS_NAME			= "aceRMS";
	public static final String	HIGH_SCORE_RMS		= "aceRMSHighScore";
	public static final int		MAX_LEVEL_RMS		= 1;
	public static final int		PREF_LANGUAGE_RMS	= 2;
	public static final int		TUTORIAL_RMS		= 3;
	public static final StringManager.Language DEFAULT_LANGUAGE = StringManager.Language.INDONESIAN;
	
	//High Score server
	public static final String SERVER = "http://www.demeister.com/btiserver";
	
	/**
	 * Private constructor
	 */
	private Utilities() {}
	
	//Static Methods
	public static String[] split(String in, String delim){
		String[] retval = null;
		Vector pos = new Vector();
		int start = 0;
		int lastPos = -1;
		
		while( (lastPos = in.indexOf(delim, start)) != -1 ){
			pos.addElement(new Integer(lastPos));
			start = lastPos + 1;
		}

		//If last element is not the end of string
		if (!pos.lastElement().equals(new Integer(in.length() - 1))) pos.addElement(new Integer(in.length()));
		
		retval = new String[pos.size()];
		
		start = 0;
		for(int i=0; i<pos.size(); ++i){
			lastPos = Integer.parseInt(pos.elementAt(i).toString());
			retval[i] = in.substring(start, lastPos).trim();
			start = lastPos + 1;
		}
		
		return retval;
	}

	public static String[] split(String in, int delim){
		String[] retval = null;
		Vector pos = new Vector();
		int start = 0;
		int lastPos = -1;
		
		while( (lastPos = in.indexOf(delim, start)) != -1 ){
			pos.addElement(new Integer(lastPos));
			start = lastPos + 1;
		}
		
        //If last element is not the end of string
		if (!pos.lastElement().equals(new Integer(in.length() - 1))) pos.addElement(new Integer(in.length()));
        
		retval = new String[pos.size()];
		
		start = 0;
		for(int i=0; i<pos.size(); ++i){
			lastPos = Integer.parseInt(pos.elementAt(i).toString());
			retval[i] = in.substring(start, lastPos).trim();
			start = lastPos + 1;
		}
		
		return retval;
	}
	
	public static Image[] splitTransparentImage(Image image, int width, int height) {
		//Calcuate column and row
		int column	= image.getWidth() / width;
		int row		= image.getHeight() / height;
		
		//Prepare images
		Image[] Final = new Image[column * row];
		for (int i = 0; i < Final.length; i++) {
			//Get image RGB
			int[] ImageRGB = new int[width * height];
			image.getRGB(ImageRGB, 0, width, width * i, 0, width, height);
			Final[i] = Image.createRGBImage(ImageRGB, width, height, true);
		}
		
		return Final;
	}

	public static Image createTintedImage(Image image, int color) {
		//Prepare images
		Image Final		= null;
		Image ImgCanvas	= Image.createImage(image.getWidth(), image.getHeight());

		//Get image RGB
		int[] ImageRGB = new int[image.getWidth() * image.getHeight()];
		image.getRGB(ImageRGB, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());

		//Create tint RGB
		int[] TintRGB = new int[ImageRGB.length];
		for (int i = 0; i < ImageRGB.length; i++)
			if ((ImageRGB[i] | 0x00FFFFFF) != 0x00FFFFFF) TintRGB[i] = color;

		//Draw data on canvas
		ImgCanvas.getGraphics().drawRGB(ImageRGB, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight(), true);
		ImgCanvas.getGraphics().drawRGB(TintRGB,  0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight(), true);

		//Get final RGB data
		int[] FinalRGB = new int[ImgCanvas.getWidth() * ImgCanvas.getHeight()];
		ImgCanvas.getRGB(FinalRGB, 0, ImgCanvas.getWidth(), 0, 0, ImgCanvas.getWidth(), ImgCanvas.getHeight());

		//Delete white pixels
		for (int i = 0; i < FinalRGB.length; i++)
			if (FinalRGB[i] == 0xFFFFFFFF) FinalRGB[i] = 0x00000000;

		//Creat and return the final image
		Final = Image.createRGBImage(FinalRGB, image.getWidth(), image.getHeight(), true);
		return Final;
	}

	public static float atan(float a) {
		if (Math.abs(a) <= 1.0f) {
			return (a /(1 + 0.28f*(a*a)));
		} else {
			float retval = (((float)Math.PI)/2.0f) - (a/((a*a) + 0.28f));
			if (a < (-1.0f)){
				return (retval - (float)Math.PI);
			} else { //if a > 1.0f
				return retval;
			}
		}
	}

	public static int fromByteArrayToInt(byte[] data) {
        ByteArrayInputStream bin = new ByteArrayInputStream(data);
        DataInputStream din = new DataInputStream(bin);
        int retval = -1;

        try {
        	retval = din.readInt();
		} catch (IOException e) {
		} finally {
			try {
				din.close();
			} catch (IOException e) {}
		}
        
        return retval;
    }

    public static byte[] fromIntToByteArray(int in) {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
			dout.writeInt(in);
			dout.close();
		} catch (IOException e) {
		} finally{
			try {
				dout.close();
			} catch (IOException e) {}
		}

        return bout.toByteArray();
    }

	public static boolean fromByteArrayToBool(byte[] data) {
        ByteArrayInputStream bin = new ByteArrayInputStream(data);
        DataInputStream din = new DataInputStream(bin);
        boolean retval = false;

        try {
        	retval = din.readBoolean();
		} catch (IOException e) {
		} finally {
			try {
				din.close();
			} catch (IOException e) {}
		}

        return retval;
    }

    public static byte[] fromBoolToByteArray(boolean in) {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
			dout.writeBoolean(in);
			dout.close();
		} catch (IOException e) {
		} finally{
			try {
				dout.close();
			} catch (IOException e) {}
		}

        return bout.toByteArray();
    }


	public static void initRMS(){
		try {
			RecordStore rs = RecordStore.openRecordStore(Utilities.RMS_NAME, true);

			if(rs.getNumRecords() == 0){
				byte[] defaultProfileCount	= fromIntToByteArray(0);				//Jumlah profile awal = 0
				rs.addRecord(defaultProfileCount, 0, defaultProfileCount.length);
			}
		} catch (RecordStoreFullException e) {
		} catch (RecordStoreNotFoundException e) {
		} catch (RecordStoreException e) {}
	}

	public static void putInt(int recordPos, int value){
		RecordStore rs = null;

		try {
			rs = RecordStore.openRecordStore(Utilities.RMS_NAME, true);

			byte[] data = fromIntToByteArray(value);
			if(rs.getNumRecords() > (recordPos - 1)) //overwrite
				rs.setRecord(recordPos, data, 0, data.length);
			else //create new
				rs.addRecord(data, 0, data.length);
		} catch (RecordStoreFullException e) {
		} catch (RecordStoreNotFoundException e) {
		} catch (RecordStoreException e) {}
		finally {
			try {
				rs.closeRecordStore();
			} catch (RecordStoreNotOpenException e) {
			} catch (RecordStoreException e) {}
		}
	}

	public static int getInt(int recordPos, int defaultValue){
		RecordStore rs = null;
		int retval = defaultValue;

		try {
			rs = RecordStore.openRecordStore(Utilities.RMS_NAME, true);

			if(rs.getNumRecords() > (recordPos - 1))
				retval = fromByteArrayToInt(rs.getRecord(recordPos));
		} catch (RecordStoreFullException e) {
		} catch (RecordStoreNotFoundException e) {
		} catch (RecordStoreException e) {
		} finally {
			try {
				rs.closeRecordStore();
			} catch (RecordStoreNotOpenException e) {
			} catch (RecordStoreException e) {}
		}

		return retval;
	}

	public static void putBool(int recordPos, boolean value){
		RecordStore rs = null;
		
		try {
			rs = RecordStore.openRecordStore(Utilities.RMS_NAME, true);

			byte[] data = fromBoolToByteArray(value);
			if(rs.getNumRecords() > (recordPos - 1)) //overwrite
				rs.setRecord(recordPos, data, 0, data.length);
			else //create new
				rs.addRecord(data, 0, data.length);
		} catch (RecordStoreFullException e) {
		} catch (RecordStoreNotFoundException e) {
		} catch (RecordStoreException e) {}
		finally {
			try {
				rs.closeRecordStore();
			} catch (RecordStoreNotOpenException e) {
			} catch (RecordStoreException e) {}
		}
	}

	public static boolean getBool(int recordPos, boolean defaultValue){
		RecordStore rs = null;
		boolean retval = defaultValue;

		try {
			rs = RecordStore.openRecordStore(Utilities.RMS_NAME, true);

			if(rs.getNumRecords() > (recordPos - 1))
				retval = fromByteArrayToBool(rs.getRecord(recordPos));
		} catch (RecordStoreFullException e) {
		} catch (RecordStoreNotFoundException e) {
		} catch (RecordStoreException e) {
		} finally {
			try {
				rs.closeRecordStore();
			} catch (RecordStoreNotOpenException e) {
			} catch (RecordStoreException e) {}
		}

		return retval;
	}
}

/*
 * RMS model:
 * |Record Position	|Data Saved		|
 * |1				|Profile Count	|
 * |2				|Profile #1		|
 * |3				|Profile #2		|
 * |4				|Profile #3		|
 * |5				|Profile #4		|
 * |6				|Profile #5		|
 */